package com.security;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @ClassName CookieFilter
 * @Description TODO
 * @Author wushaopei
 * @Date 2021/5/16 22:41
 * @Version 1.0
 */
@Component
@Slf4j
public class CookieFilter extends ZuulFilter {

  private RestTemplate restTemplate = new RestTemplate();

  @Override
  public String filterType() {
    return "pre";
  }

  @Override
  public int filterOrder() {
    return 1;
  }

  @Override
  public boolean shouldFilter() {
    return true;
  }

  @Override
  public Object run() throws ZuulException {

    RequestContext requestContext = RequestContext.getCurrentContext();
    HttpServletRequest request = requestContext.getRequest();
    HttpServletResponse response = requestContext.getResponse();

    String accessToken = getCookie("imooc_access_token");
    if (StringUtils.isNotBlank(accessToken)){
      requestContext.addZuulRequestHeader("Authorization","bearer " + accessToken);
    }else {
      String refreshToken = getCookie("imooc_refresh_token");
      if (StringUtils.isNotBlank(refreshToken)){
          //认证服务器验token地址 /oauth/check_token 是  spring .security.oauth2的验token端点
          String oauthServiceUrl = "http://gateway.imooc.com:9070/token/oauth/token";

          HttpHeaders headers = new HttpHeaders();
          headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // 不是json请求
          // 网关的appId，appSecret，需要在数据库oauth_client_details注册
          headers.setBasicAuth("admin","123456");
          // 封装token
          MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
          params.add("refresh_token",refreshToken); // 刷新令牌
          params.add("grant_type","refresh_token"); //授权类型-刷新令牌模式
          log.info("CookieFilter the refresh_token is: {}", refreshToken);
          HttpEntity<MultiValueMap<String,String>> entity = new HttpEntity<>(params,headers);

          try{
            ResponseEntity<TokenInfo> newToken = restTemplate.exchange(oauthServiceUrl, HttpMethod.POST,entity,TokenInfo.class);
            // 第二种方式：基于token实现的SSO
            // 这里是添加到zuul网关的请求头
            requestContext.addZuulRequestHeader("Authorization","bearer " + newToken);
            // access_token
            Cookie accessTokenCookie = new Cookie("imooc_access_token",newToken.getBody().getAccess_token());
            accessTokenCookie.setMaxAge(newToken.getBody().init().getExpires_in().intValue()-3);
            accessTokenCookie.setDomain("imooc.com");
            accessTokenCookie.setPath("/");
            response.addCookie(accessTokenCookie);
            // refresh_token
            Cookie refreshTokenCookie = new Cookie("imooc_refresh_token",newToken.getBody().getRefresh_token());
            accessTokenCookie.setMaxAge(2592000);
            accessTokenCookie.setDomain("imooc.com");
            accessTokenCookie.setPath("/");
            response.addCookie(refreshTokenCookie);
            log.info("access_token is null, refresh_token:{} --- get access_token :{}" , refreshToken, accessToken);
          }catch (Exception e){
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(500);
            requestContext.setResponseBody("{\"message\":\"refresh fail\"}");
            requestContext.getResponse().setContentType("application/json");
          }
      }else {
        requestContext.setSendZuulResponse(false);
        requestContext.setResponseStatusCode(500);
        requestContext.setResponseBody("{\"message\":\"refresh fail\"}");
        requestContext.getResponse().setContentType("application/json");
      }
    }

    return null;
  }

  // 获取cookie
  public String getCookie(String name) {
    String result = null;

    RequestContext requestContext = RequestContext.getCurrentContext();
    HttpServletRequest request = requestContext.getRequest();

    Cookie[] cookies = request.getCookies();

    for (Cookie cookie : cookies){
      if (StringUtils.equals(name,cookie.getName())){
        result = cookie.getValue();
        break;
      }
    }
    return result;
  }
}
